package heuristics;

import java.util.LinkedList;
import java.util.List;

import Entities.Calendar;
import Entities.Course;

public class WorkingStudentHeuristic implements IHeuristic {
	final static int maxCoursesToTake = 7;
	final static int MIN_TIME_DIFF = 2;
	final static int TIME_DIFF_FACTOR = 5;

	@Override
	public double evaluate(Calendar toEvaluate) {
		double heuristicValue = 0;
		int numberOfCollisions = 0;

		if (toEvaluate == null){
			throw new IllegalArgumentException("Illegal calendar to evaluate");
		}
		List<Course> courses = new LinkedList<Course>(toEvaluate.getCourses());
		// check if calendar is empty or calendar has collisions
		if (!toEvaluate.isEmpty()) // else 0 will returned
		{
			numberOfCollisions = toEvaluate.getNumberOfCollisions();
			if (numberOfCollisions > 0){
				heuristicValue = (-1)* numberOfCollisions;
			}
			else{	// calendar without collisions
				int numberOfCourses = courses.size(); 
				if (numberOfCourses > maxCoursesToTake){
					heuristicValue -= numberOfCourses; 
				}
				
				substractFarCourses(courses, heuristicValue);
				
				List<Course> coursesWithoutAdjacents = toEvaluate.getCoursesWithoutAdjacents();
				courses.removeAll(coursesWithoutAdjacents);
				
		
				// adding course load and grade factors
				for (Course course : courses) {
					if (course.getWorkLoad() < Calendar.getAverageWorkload()){
						heuristicValue += (Course.MaxWorkLoad - course.getWorkLoad());				
					}
					heuristicValue += (course.getAverageGrade()*averageGradeNormalizationFactor);
				}
			
				if (heuristicValue < 0){
					heuristicValue = 0;
				}
			}
		}
		return heuristicValue;
	}
	
	/**
	 * Subtracting fixed factor for each course that is far at least 
	 * MIN_TIME_DIFF from all other courses in calendar
	 */
	private void substractFarCourses(List<Course> courses, double heuristicValue) {
		// subtracting for each course that is far from the current calendar 2 hours and more
		int courseTime;
		boolean isFarCourse = true;
		
		for (Course course : courses) {
			courseTime = course.getTime();
			for (Course comperableCourse: courses) {
				if ((comperableCourse != course) && (Math.abs(courseTime - comperableCourse.getTime()) <= MIN_TIME_DIFF)){
					isFarCourse = false;
				}
			}
			if (true == isFarCourse){
				heuristicValue -= TIME_DIFF_FACTOR;				
			}
			isFarCourse = true; // for next course
		}
	}

	@Override
	public int getMaxNumberOfCourses() {
		return maxCoursesToTake;
	}
	
	public String toString(){
		return "Working Student Heuristic";
	}
}
